﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace OwElectrePromethee
{
    class Electre1S : IOwMethod
    {
        public string Perform(bool fromFile = true)
        {
            List<EKryterium> kryteria = ElectreTri.LoadKryteria();
            List<EWariant> warianty = ElectreTri.LoadWarianty();
            ElectreTri.CheckKryteria(kryteria, warianty);

            double progOdciecia = 0.55d;

            //test zgodności
            EPrzewyższanie[,] compliance = new EPrzewyższanie[warianty.Count, warianty.Count];



            using (TextWriter writer = new StreamWriter("output.txt"))
            {
                foreach (var wariant_outer in warianty)
                {
                    writer.WriteLine("wariant {0}", wariant_outer.ToString());
                    foreach (var wariant_inner in warianty)
                    {
                        writer.WriteLine(" profil {0}", wariant_inner.ToString());

                        var comparisionList = new List<Tuple<int, double>>();

                        //ok, mam konkretny wariant i profil, porównuję je
                        foreach (var kryterium in kryteria)// porównuję każdy wariant ze wszystkimi profilami, na każdym kryterium
                        {

                            var wariantKryteriumValue = wariant_outer.K.First(k => k.Id == kryterium.Id).Value;
                            var profilKryteriumValue = wariant_inner.K.First(k => k.Id == kryterium.Id).Value;

                            var relacja = kryterium.Compare(wariantKryteriumValue, profilKryteriumValue);

                            if (relacja != ERelacje.Nieporownywalne)//wyliczam cząstkowy wsp. zgodności
                            {
                                var ci = kryterium.getCi(wariantKryteriumValue, profilKryteriumValue);
                                comparisionList.Add(new Tuple<int, double>(kryterium.Id, ci));
                                writer.WriteLine("  kryterium {0}, Rel: {1}, Ci: {2}", kryterium, relacja, ci);

                            }
                            else writer.WriteLine("  kryterium {0}, Rel: {1}", kryterium, relacja);
                        }

                        if (!comparisionList.Any()) compliance[wariant_outer.Id - 1, wariant_inner.Id - 1] = EPrzewyższanie._1;
                        else
                        {
                            var CiWeighted = comparisionList.Select(Ci => Ci.Item2 * kryteria.First(k => k.Id == Ci.Item1).Waga).ToList();
                            var Weights = comparisionList.Select(Ci => kryteria.First(k => k.Id == Ci.Item1).Waga).ToList();

                            double cGlobal = CiWeighted.Sum() / Weights.Sum();
                            writer.WriteLine("\tWsp. zgodności: {0}", cGlobal);

                            if (cGlobal >= progOdciecia) //Test niezgodności
                            {
                                bool veto = false;
                                foreach (var kryterium in kryteria)
                                {
                                    var wariantKryteriumValue = wariant_outer.K.First(k => k.Id == kryterium.Id).Value;
                                    var profilKryteriumValue = wariant_inner.K.First(k => k.Id == kryterium.Id).Value;
                                    var relacja = kryterium.Compare(wariantKryteriumValue, profilKryteriumValue);

                                    if (relacja != ERelacje.Nieporownywalne)
                                    {
                                        if (kryterium.Typ == EKryteriumTyp.Zysk)
                                        {
                                            using (TextWriter writer2 = new StreamWriter("niezgodnosc.txt", true))
                                            {
                                                if (profilKryteriumValue - wariantKryteriumValue >= kryterium.V)
                                                    veto = true;
                                                writer2.WriteLine("Wariant:{0} Profil:{1} Kryt:{2} veto = vetoCalc:{3} >= {4} ({5})",
                                                    wariant_outer.Id, wariant_inner.Id, kryterium.Id, profilKryteriumValue - wariantKryteriumValue,
                                                    kryterium.V, profilKryteriumValue - wariantKryteriumValue >= kryterium.V);
                                            }
                                        }
                                        else if (kryterium.Typ == EKryteriumTyp.Koszt)
                                        {
                                            using (TextWriter writer2 = new StreamWriter("niezgodnosc.txt", true))
                                            {
                                                if (profilKryteriumValue - wariantKryteriumValue <= kryterium.V)
                                                    veto = true;
                                                writer2.WriteLine("Wariant:{0} Profil:{1} Kryt:{2} veto = vetoCalc:{3} <= {4} ({5})",
                                                    wariant_outer.Id, wariant_inner.Id, kryterium.Id, profilKryteriumValue - wariantKryteriumValue,
                                                    kryterium.V, profilKryteriumValue - wariantKryteriumValue <= kryterium.V);
                                            }
                                        }
                                    }
                                }
                                if (!veto) compliance[wariant_outer.Id - 1, wariant_inner.Id - 1] = EPrzewyższanie.SS;
                                else compliance[wariant_outer.Id - 1, wariant_inner.Id - 1] = EPrzewyższanie.SS; //TODO: tu powinno być weto, ale nie znam zasady działania veta
                            }
                            else compliance[wariant_outer.Id - 1, wariant_inner.Id - 1] = EPrzewyższanie._S;
                        }
                    }
                    writer.WriteLine();
                }
            }

            return FindOrder(compliance);
            //return EPorównanieHelper.Rysuj(compliance);


        }


        public static string FindOrder(EPrzewyższanie[,] compliance)
        {
            var list = new List<Tuple<int, int>>();
            for (var wariantId = 0; wariantId < compliance.GetLength(0); wariantId++ )
            {
                int sum = 0;
                for ( var wariantId2 = 0; wariantId2 < compliance.GetLength(1); wariantId2++)
                {
                    if (compliance[wariantId, wariantId2] == EPrzewyższanie.SS) sum++;
                }
                list.Add(new Tuple<int, int>(wariantId, sum));
            }

            list = list.OrderByDescending(m => m.Item2).ToList();


            var ret = new StringBuilder();

            foreach (Tuple<int, int> tuple in list)
            {
                ret.AppendFormat("wariant {0}\n", tuple.Item1);
            }

                return ret.ToString();
        }
    }
}
